﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Face8280WebSocketServer.DB.Device;
using Face8280WebSocketServer.DB.User;
using Face8280WebSocketServer.Interface;
using Microsoft.EntityFrameworkCore;
using Newtonsoft.Json;
using Face8280WebSocketServer.DB;
using Face8280WebSocketServer.Utility.Model;
using System.Linq.Expressions;
using Face8280WebSocketServer.Utility.ExpressionExtend;
using Newtonsoft.Json.Serialization;
using Face8280WebSocketServer.DTO.FaceDevice;
using Face8280WebSocketServer.DTO;

namespace Face8280WebSocketServer.Service
{
    /// <summary>
    /// 人脸机设备操作服务
    /// </summary>
    public class FaceDriveService : BaseService, IFaceDriveService
    {
        private ICacheService _Cache;

        public FaceDriveService(DbContext context, ICacheService cache) : base(context)
        {
            _Cache = cache;
        }

        /// <summary>
        /// 分页查询设备信息
        /// </summary>
        /// <returns></returns>
        public PageResult<FaceDeviceDetail_PageModel> GetDevicePage(List<Expression<Func<FaceDeviceDetail, bool>>> oWheres, BasePageParameter page)
        {
            var devices = QueryPage(
            x => new FaceDeviceDetail_PageModel()
            {
                ID = x.ID,
                DeviceID = x.DeviceID,
                DeviceName = x.DeviceName,
                ParameterAccessType = x.ParameterAccessType,
                ParameterKeepOpenDoor = x.ParameterKeepOpenDoor,
                ParameterLaissezSwitch = x.ParameterLaissezSwitch,
                ParameterProductionDate = x.ParameterProductionDate,
                ParameterFirmwareMsg = x.ParameterFirmwareMsg
            },
            oWheres, page.pageSize, page.pageIndex,
            x => x.DeviceID,
            page.isAsc);

            if (devices.DataList.Count > 0)
            {   //查询缓存
                {
                    /*
                    var oCatchDevices = _Cache.GetDevices(devices.DataList.Select(x => x.DeviceID).ToList());
                    var olinq = from d in devices.DataList
                                join c in oCatchDevices
                                on d.DeviceID equals c.DeviceID
                                select new FaceDeviceDetail_PageModel()
                                {
                                    DeviceID = d.DeviceID,
                                    DeviceName = d.DeviceName,
                                    ParameterAccessType = d.ParameterAccessType,
                                    ParameterKeepOpenDoor = d.ParameterKeepOpenDoor,
                                    ParameterLaissezSwitch = d.ParameterLaissezSwitch,
                                    ParameterProductionDate = d.ParameterProductionDate,
                                    ParameterFirmwareMsg = d.ParameterFirmwareMsg,
                                    LastKeepaliveTime = c.LastKeepaliveTime,
                                    OnlineTime = c.OnlineTime,
                                    AlarmStatus = c.AlarmStatus,
                                    DoorStatus = c.DoorStatus
                                };
                    devices.DataList = olinq.ToList();
                    */
                }
                _Cache.GetDeviceOnlineStatus(devices.DataList);
            }
            return devices;
        }

        public List<FaceDeviceDetail_PageModel> GetDeviceOnlineStatus(List<string> SNList)
        {
            List<FaceDeviceDetail_PageModel> oModel = SNList.Select(x => new FaceDeviceDetail_PageModel() { DeviceID = x }).ToList();

            return _Cache.GetDeviceOnlineStatus(oModel);
        }

        public bool Add(FaceDeviceDetail oDevice)
        {
            FaceDeviceDetail oDBModel = GetDetailByDB(oDevice.DeviceID);
            if (oDBModel == null)
            {
                if (string.IsNullOrWhiteSpace(oDevice.ParameterWifiPassWord))
                    oDevice.ParameterWifiPassWord = string.Empty;
                oDBModel = Insert<FaceDeviceDetail>(oDevice);
              //  _Cache.AddDeviceCache(oDBModel);
                CurrentUser = new UserDetail() { UserID = 1, UserName = "Auto" };
                AddUserLog("设备管理", $"{oDevice.DeviceID} 设备上报参数，自动新增入库。\r\n{oDevice.ToJson()}");
                return true;
            }
            else
            {
                //2021年7月22日 增加参数覆盖功能
                oDBModel = Find<FaceDeviceDetail>(oDBModel.ID);
                oDevice.CopyToWorkPar(oDBModel);
                oDevice.CopyToNetWork(oDBModel);
                //oDBModel.ConnectType = oDevice.ConnectType;
                //oDBModel.DeviceIP = oDevice.DeviceIP;
                //oDBModel.DevicePort = oDevice.DevicePort;
                oDBModel.ParameterFirmwareMsg = oDevice.ParameterFirmwareMsg;//固件版本信息
                Commit();
                return true;
            }
        }

        public bool AddNew(DB.NewModel.Device.FaceDeviceDetailNew oDevice)
        {
            var oDBModel = GetDeviceDetailNewById(oDevice.DeviceId);
            if (oDBModel == null)
            {
                oDBModel = Insert(oDevice);
            }
            else
            {
                // oDBModel.Copy(oDevice);
                //   Commit();
            }
            return true;
        }

        //  public bool AddIpPar()
        public DB.NewModel.Device.FaceDeviceDetailNew GetDeviceDetailNewById(string deviceId)
        {
            var devices = Query<DB.NewModel.Device.FaceDeviceDetailNew>(x => x.DeviceId.Equals(deviceId)).Take(1);
            if (devices.Count() == 0)
            {
                return null;
            }
            var device = devices.First();
            return device;
        }

        public DbSet<FaceDeviceDetail> GetDBSet()
        {
            return this.Context.Set<FaceDeviceDetail>();
        }

        #region 默认值
        public FaceDeviceDetail GetDefaultValue()
        {
            var sysdb = GetSystemKVDBSet();
            var kv = sysdb.Find("DefaultDevice");
            FaceDeviceDetail par = new();
            if (kv == null)
            {
                par = GetDefaultBaseParameter();
            }
            else
            {
                try
                {
                    par = JsonConvert.DeserializeObject<FaceDeviceDetail>(kv.Value);
                }
                catch (Exception)
                {

                    par = GetDefaultBaseParameter();
                }

            }

            return par;
        }


        public void SaveDefaultValue(FaceDeviceDetail def)
        {
            var sysdb = GetSystemKVDBSet();
            var kv = sysdb.Find("DefaultDevice");
            var sJson = JsonConvert.SerializeObject(def);


            AddUserLog("设备管理", $"更新设备出厂默认值：{sJson}");


            if (kv == null)
            {
                kv = new() { Key = "DefaultDevice", Value = sJson };
                Insert(kv);
            }
            else
            {
                kv.LastUpdateTime = DateTime.Now;
                kv.Value = sJson;
                Commit();

            }
        }


        /// <summary>
        /// 获取默认的出厂参数
        /// </summary>
        /// <returns></returns>
        private FaceDeviceDetail GetDefaultBaseParameter()
        {
            FaceDeviceDetail target = new();
            target.DeviceID = "FC-8280T00000000";//设备ID

            #region 语音
            target.ParameterVolume = 10;//音量大小(范围0-10)
            target.ParameterVoiceMode = 3;//语音模式0,不播报；1，播放名字;2,播放问候语;3,播放名字和问候语
            target.ParameterGrettings = 0;//问候语0，请通行;1,欢迎光临;2，时间问候语
            target.ParameterStrangerVoice = 2;//陌生人语音0，不播报;1,播报假体;2，播报陌生人；3，播报假体和陌生人
            #endregion

            #region 补光灯
            target.ParameterLightSwitch = 1;//补光灯开关：0：常闭；  1：常开； 2：自动；
            #endregion

            #region UI界面
            target.ParameterBrightness = 10;//亮度设置1-10
            target.ParameterExposure = 0;// 曝光设置
            target.ParameterIR = 0;//红外图像开关
            target.ParameterCompanyName = "FCARD";//主界面设置--公司名称
            target.ParameterLanguageChoose = 0;//语言选择0，中文；1，英文；2，繁体
            target.ParameterLoginPassword = "";//菜单密码
            #endregion

            #region 身份信息
            //target.ParameterFirmwareMsg = src.ParameterFirmwareMsg;//固件版本信息
            target.ParameterSerialNum = target.DeviceID;//序列号
            target.ParameterManufacturer = "FCARD";//制造商
            target.ParameterWebsite = "http://www.pc15.net";//网址
            target.ParameterProductionDate = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");//生产日期
            #endregion

            #region 记录存储
            target.ParameterSaveExternalvisitors = 1;//是否存储非雇员识别记录，0:不存储，1:存储
            target.ParameterSavePicture = 1;//保存现场图片 0，不保存；1，保存
            #endregion

            #region 人脸识别
            target.ParameterPreview = 1;//活体检测,1打开，0关闭
            target.ParameterFaceIRThreshold = 6;
            target.ParameterDistance = 2;//识别距离 1--远（默认值）、2--中、3--近  
            target.ParameterFaceThreshold = 70;//人脸识别阈值
            target.ParameterMask = 1;//1：打开口罩检测，其他：关闭
            target.ParameterMaskThreshold = 60;//口罩阈值
            #endregion

            #region 体温检测
            target.ParameterTempSwitch = 1;//测温模式开关，0关闭，1打开
            target.ParameterFahrenheitSwitch = 0;//开启华氏温度,1:开，0:关
            target.ParameterCompensate = 0;// -1 -- 1 ,温度补偿值
            target.ParameterTempThresholdMax = 37.6f;//温度比对阈值（最大值）
            #endregion

            #region 网络参数
            target.ParameterCloudserverAddress = "";//服务器地址
            target.ParameterPolling = 10;//主动触发云端轮训时间（以秒为单位）

            #endregion


            #region 门禁参数
            target.ParameterAccessType = 0;//出入类型0,入门；1，出门

            target.ParameterWgFormat = 34;//WG输出格式26/34
            target.ParameterKeepOpenDoor = 3;//开门保持时间1-65535（s）
            target.ParameterLaissezSwitch = 0;//免验证开门1--启用；0--禁用
            target.ParameterRecgInterval = 10;//识别间隔0--禁用;1-65535（s）
            target.ParameterIntervalRecoSwitch = 0;//间隔记录存储设置0,关闭；1，打开
            target.ParameterDoorLongOpenAlarmSwitch = 0;//开门超时报警开关，0，关闭；1，开启
            target.ParameterDoorSensorDelay = 60;//开门超时时间，门打开超过这个时间就报警	5-255（s）
            target.ParameterDoorAlarmSwitch = 0;//门磁报警，0，关闭；1，开启
            #endregion

            return target;
        }
        #endregion



        /// <summary>
        /// 从数据库获取权限统计信息
        /// </summary>
        /// <param name="oDevice"></param>
        /// <returns></returns>
        public (int NewPeople, int DelPeople, int RemoteCount, int AccessTotal) GetTaskTotalByDB(FaceDeviceDetail oDevice)
        {
            var ret = (NewPeople: 0, DelPeople: 0, RemoteCount: 0, AccessTotal: 0);
            //加载设备权限统计数
            var query = from device in Set<FaceDeviceDetail>()
                        join dAccess in Set<FacePeopleAccessDetail>()
                        on device.ID equals dAccess.DeviceID
                        where dAccess.UploadStatus == 0 && device.ID == oDevice.ID
                        select dAccess.AccessID
                        ;
            ret.NewPeople = query.Count();

            //查询待删除
            query = from device in Set<FaceDeviceDetail>()
                    join dAccess in Set<FacePeopleAccessDetail>()
                    on device.ID equals dAccess.DeviceID
                    where dAccess.UploadStatus == 2 && device.ID == oDevice.ID
                    select dAccess.AccessID
                        ;
            ret.DelPeople = query.Count();

            //查询所有
            query = from device in Set<FaceDeviceDetail>()
                    join dAccess in Set<FacePeopleAccessDetail>()
                    on device.ID equals dAccess.DeviceID
                    where dAccess.UploadStatus < 2 && device.ID == oDevice.ID
                    select dAccess.AccessID
                        ;
            ret.AccessTotal = query.Count();

            //加载所有任务
            query = from device in Set<FaceDeviceDetail>()
                    join dTask in Set<RemoteTaskDetail>()
                    on device.ID equals dTask.DeviceID
                    where dTask.TaskStatus == 0 && device.ID == oDevice.ID
                    select dTask.TaskID
                    ;
            ret.RemoteCount = query.Count();
            query = null;

            return ret;
        }

        private FaceDeviceDetail GetDetailByDB(string sn)
        {
            var devices = Query<FaceDeviceDetail>(x => x.DeviceID.Equals(sn)).Take(1);
            if (devices.Count() == 0)
            {
                return null;
            }
            var device = devices.First();
            return device;
        }

        public JsonResultModel Update(FaceDeviceDetail oDevice)
        {
            var device = Find<FaceDeviceDetail>(oDevice.ID);
            if (device == null) return new JsonResultModel(200, "设备不存在");

            #region 重复过滤
            List<Expression<Func<FaceDeviceDetail, bool>>> oWheres = new();
            oWheres.Add(x => x.ID != oDevice.ID);
            Expression<Func<FaceDeviceDetail, bool>> w1 = x => x.DeviceID.Equals(oDevice.DeviceID);
            Expression<Func<FaceDeviceDetail, bool>> w2 = x => x.DeviceName.Equals(oDevice.DeviceName);
            oWheres.Add(w1.Or(w2));

            var devices = QueryPage(
                x => new
                {
                    x.ID,
                    x.DeviceID,
                    x.DeviceName
                },
                oWheres, 100, 1,
                x => x.DeviceID,
                true, true);
            if (devices.TotalCount > 0)
            {
                foreach (var p in devices.DataList)
                {
                    if (p.DeviceID == oDevice.DeviceID)
                    {
                        return new JsonResultModel(201, $"设备SN重复");
                    }
                    if (p.DeviceName == oDevice.DeviceName)
                    {
                        return new JsonResultModel(202, $"设备名称重复");
                    }
                }

            }
            #endregion

            //_logger.LogInformation($"更新设备：ID:{device.ID} SN:{device.DeviceID} Name:{device.DeviceName}");
            string SN = device.DeviceID;
            oDevice.CopyTo(device);
            device.DeviceID = SN;
            oDevice.DeviceID = SN;

            device.UploadStatus = 0;
            device.LastUpdatetime = DateTime.Now;

            //更新缓存
           // _Cache.UpdateDeviceCache(oDevice, GetTaskTotalByDB(oDevice));


            AddUserLog("设备管理",
                $"修改设备参数：{device.DeviceName}({device.DeviceID})，参数信息：{JsonConvert.SerializeObject(device)}",
                $"{device.DeviceName}({device.DeviceID})", string.Empty);

            //base.Update(device);
            Commit();
            return new JsonResultModel(new { device.ID });
        }

        public bool Delete(List<int> DeviceIDs)
        {
            var db = Context.Set<FaceDeviceDetail>();
            //查询需要删除的设备
            HashSet<int> devIDLists = new HashSet<int>(DeviceIDs);
            var devices = db.Where(x => devIDLists.Contains(x.ID)).Select(x => new FaceDeviceDetail
            {
                ID = x.ID,
                DeviceName = x.DeviceName,
                DeviceID = x.DeviceID
            });
            foreach (var d in devices)
            {
                AddUserLog("设备管理", $"删除设备：{d.DeviceName}({d.DeviceID})",
                $"{d.DeviceName}({d.DeviceID})", string.Empty);
                db.Remove(d);
            }

            //更新缓存
         //   _Cache.DeleteDeviceCache(devices.ToList());

            Commit();

            return true;
        }

        public void FormatDevice(int iDeviceID)
        {
            var deviceDetail = Find<FaceDeviceDetail>(iDeviceID);
            deviceDetail.UploadStatus = 0;
            deviceDetail.LastUpdatetime = DateTime.Now;
            this.Commit();

            Excute("Update FacePeopleAccessDetail set UploadStatus = 0 ,LastUpdatetime={0} where DeviceID = {1} and UploadStatus = 1",
                DateTime.Now, iDeviceID);

            Excute("delete from  FacePeopleAccessDetail where DeviceID = {0} and UploadStatus = 2", iDeviceID);
            //更新到缓存

            var totalDetail = GetTaskTotalByDB(deviceDetail);
           // _Cache.UpdateDeviceCache(deviceDetail, totalDetail);
        }

        public void UpdateDeviceSoft(string url, string ver, string softMD5, int deviceID)
        {
            var deviceDetail = Find<FaceDeviceDetail>(deviceID);
            deviceDetail.UploadStatus = 0;
            deviceDetail.LastUpdatetime = DateTime.Now;
            this.Commit();

            //_Cache.UpdateDeviceCache(deviceDetail, (c, d) =>
            //{
            //    c.Add("UploadStatus", "0");
            //    c.Add("UploadStatusTime", deviceDetail.LastUpdatetime.ToDateTimeStr());
            //    c.Add("UpdateSoftURL", url);
            //    c.Add("UpdateSoftVer", ver);
            //    c.Add("UpdateSoftMD5", softMD5);
            //});
        }

    }
}
